package com.inspur.edp.udt.designtime.manager.services;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.cef.designtime.api.operation.CommonOperation;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import com.inspur.edp.udt.designtime.api.entity.validation.ValidationInfo;
import com.inspur.edp.udt.designtime.api.exception.UdtModelErrorCodeEnum;
import com.inspur.edp.udt.designtime.api.exception.UdtModelException;
import com.inspur.edp.udt.designtime.api.utils.UdtUtils;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.ArrayList;
import java.util.List;

public class MetadataReferenceService implements IMetadataReferenceManager {

    @Override
  public List<MetadataReference> getConstraint(GspMetadata metadata) {
    if (metadata.getRefs() != null) {
      metadata.getRefs().clear();
    }
    buildMetadataReference(metadata);
    List<MetadataReference> list = new ArrayList<>();
    if (metadata.getRefs() != null && metadata.getRefs().size() > 0) {
      for (MetadataReference item : metadata.getRefs()) {
        list.add(item);
      }
    }
    return list;
  }

  private void buildMetadataReference(GspMetadata metadata) {
    if (metadata.getRefs() == null) {
      metadata.setRefs(new ArrayList<MetadataReference>());
    }

    MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
    UnifiedDataTypeDef udt = (UnifiedDataTypeDef) metadata.getContent();

    if (udt instanceof SimpleDataTypeDef) {
      buildSimpleDataTypeDefReference((SimpleDataTypeDef) udt, metadata, metadataService);
    } else if (udt instanceof ComplexDataTypeDef) {
      buildComplexDataTypeDefReference((ComplexDataTypeDef) udt, metadata, metadataService);
    } else {
      throw UdtModelException.createException(UdtModelErrorCodeEnum.GSP_BEMODEL_ENUM_NOTSUPPORT_0005, udt == null? "Null" : udt.getClass().getSimpleName());
    }
  }

  private void buildComplexDataTypeDefReference(ComplexDataTypeDef cUdt, GspMetadata metadata,
      MetadataService metadataService) {

    // ① 字段
    if (cUdt.getElements() != null && cUdt.getElements().size() > 0) {
      for (IGspCommonField ele : cUdt.getElements()) {
        dealElementReference((UdtElement) ele, metadata, metadataService);
      }
    }
    // ② val
    if (cUdt.getValidations() != null && cUdt.getValidations().size() > 0) {
      for (ValidationInfo val : cUdt.getValidations()) {
        buildUdtValidationInfoReference(val, metadata, metadataService);
      }
    }
    // ③ dtm
    DealCommonDtmCollection(cUdt.getDtmAfterCreate(), metadata, metadataService);
    DealCommonDtmCollection(cUdt.getDtmAfterModify(), metadata, metadataService);
    DealCommonDtmCollection(cUdt.getDtmBeforeSave(), metadata, metadataService);
  }

  private void DealCommonDtmCollection(CommonDtmCollection dtms, GspMetadata metadata,
      MetadataService metadataService) {
    if (dtms != null && dtms.getCount() > 0) {
      for (CommonDetermination dtm : dtms) {
        BuildCommonOpReference(dtm, metadata, metadataService);
      }
    }
  }

  public void BuildCommonOpReference(CommonOperation operation, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(operation.getComponentId(), metadata, metadataService);
  }


  private void dealElementReference(UdtElement element, GspMetadata metadata,
      MetadataService metadataService) {

  }

  private void buildSimpleDataTypeDefReference(SimpleDataTypeDef sUdt, GspMetadata metadata,
      MetadataService metadataService) {
    // ① 关联be
    if (sUdt.getObjectType() == GspElementObjectType.Association) {
      if (sUdt.getChildAssociations() != null && sUdt.getChildAssociations().size() > 0) {
        for (GspAssociation asso : sUdt.getChildAssociations()) {
          buildAssociationReference(asso, metadata, metadataService);
        }
      }
    }

    // ② val
    if (sUdt.getValidations() != null && sUdt.getValidations().size() > 0) {
      for (ValidationInfo val : sUdt.getValidations()) {
        buildUdtValidationInfoReference(val, metadata, metadataService);
      }
    }
  }

  private void buildUdtValidationInfoReference(ValidationInfo valInfo, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(valInfo.getCmpId(), metadata, metadataService);
  }

  private void buildAssociationReference(GspAssociation asso, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(asso.getRefModelID(), metadata, metadataService);

  }

  private void buildReference(String refMetadataId, GspMetadata metadata,
      MetadataService metadataService) {
    if (UdtUtils.checkNull(refMetadataId)) {
      return;
    }
    if (metadata.getRefs().stream()
        .anyMatch(item -> item.getDependentMetadata().getId().equals(refMetadataId))) {
      return;
    }

    RefCommonService refService = SpringBeanUtils.getBean(RefCommonService.class);
    GspMetadata refMetaData = refService.getRefMetadata(refMetadataId);
    if (refMetaData == null) {
      throw UdtModelException.createException(UdtModelErrorCodeEnum.GSP_BEMODEL_UDT_MODEL_0008);
    }

    MetadataReference reference = new MetadataReference() {
      {
        setMetadata(metadata.getHeader());
        setDependentMetadata(refMetaData.getHeader());
      }
    };
    metadata.getRefs().add(reference);
  }

}